#include "Aquarium_Device.h";

extern LiquidCrystal     lcd;
extern Clock                           clock;
extern Aquarium_Modes   aquarium_modes;
extern  Temp                             temp;

void  Aquarium_Device::init(byte _DeviceNum,int _PinNum,void (*ON_OFF_Func)(bool Val, byte DeviceNum)) {
  Device_ON_OFF = ON_OFF_Func; 
  int address = EEPROM_DEVICE_ADDRESS_START + (EEPROM_DEVICE_ADDRESS_OFFSET* _DeviceNum) ;

  DeviceNum = _DeviceNum;
  PinNum = _PinNum;
  pinMode(PinNum, OUTPUT);
  
  Device_Mode = EEPROM.read(address++) ;
  Aquarium_modes = EEPROM.read(address++) ;

  for ( int i = 0 ; i < DEVICE_NUMBER_OF_TIMERS ; ++i ){
    Timer_On[i] =   EEPROM.read(address++) ;
    Start_Timer_HR[i] = EEPROM.read(address++) ;
    Start_Timer_MIN[i] = EEPROM.read(address++) ;
    End_Timer_HR[i] = EEPROM.read(address++) ;
    End_Timer_MIN[i] = EEPROM.read(address++) ;
  }
  Temp_switch = 0;
  for ( int i = 0 ; i < TEMP_NUMBER_OF_PROBES ; ++i ){
    Temp_His_byte[i]  = EEPROM.read(address++) ;
    Temp_His[i] = ((float)Temp_His_byte[i])  / 100;

    Temp_High_Mode[i]  = EEPROM.read(address++) ;
    Temp_High_h[i]= EEPROM.read(address++) ;
    Temp_High_l[i]= EEPROM.read(address++) ;    
    Temp_High[i] = temp.get_temp(Temp_High_h[i],Temp_High_l[i]);

    Temp_Low_Mode[i]= EEPROM.read(address++) ;
    Temp_Low_h[i]= EEPROM.read(address++) ;
    Temp_Low_l[i]= EEPROM.read(address++) ;
    Temp_Low[i]= temp.get_temp(Temp_Low_h[i],Temp_Low_l[i]);
  }
}

void Aquarium_Device::Save_To_EEPROM(){
  int address = EEPROM_DEVICE_ADDRESS_START + (EEPROM_DEVICE_ADDRESS_OFFSET* DeviceNum) ;

  EEPROM.write(address++, Device_Mode) ;
  EEPROM.write(address++,Aquarium_modes ) ;

  for ( int i = 0 ; i < DEVICE_NUMBER_OF_TIMERS ; ++i ){
    EEPROM.write(address++, Timer_On[i]) ;
    EEPROM.write(address++,Start_Timer_HR[i] ) ;
    EEPROM.write(address++, Start_Timer_MIN[i]) ;
    EEPROM.write(address++,End_Timer_HR[i]  ) ;
    EEPROM.write(address++,End_Timer_MIN[i] ) ;
  }

  for ( int i = 0 ; i < TEMP_NUMBER_OF_PROBES ; ++i ){
    EEPROM.write(address++, Temp_His_byte[i] ) ;

    EEPROM.write(address++,Temp_High_Mode[i]  ) ;
    EEPROM.write(address++,Temp_High_h[i] ) ;
    EEPROM.write(address++, Temp_High_l[i]) ;

    EEPROM.write(address++,Temp_Low_Mode[i] ) ;
    EEPROM.write(address++, Temp_Low_h[i]) ;
    EEPROM.write(address++, Temp_Low_l[i]) ;
  }
}
void Aquarium_Device::Turn_On(){
  digitalWrite(PinNum, HIGH);    
  //Device_ON_OFF(true, DeviceNum);
}

void Aquarium_Device::Turn_Off(){
  digitalWrite(PinNum, LOW);    
 //  Device_ON_OFF(false, DeviceNum);
}


// return true if the device should be on
bool Aquarium_Device::Check_Aquarium_mode(byte Aquarium_mode){
  return  bitRead(Aquarium_modes,Aquarium_mode ) == 1;
}

void Aquarium_Device::Set_Aquarium_mode(byte Aquarium_mode,byte val){
  bitWrite(Aquarium_modes, Aquarium_mode, val);
}

// return true if the device should be turn on
bool Aquarium_Device::Check_Timer(byte Cur_Hr,byte Cur_Min){
  bool res = true;
  for ( byte timer_num = 0 ; timer_num <  DEVICE_NUMBER_OF_TIMERS ; ++timer_num){
    if ( Timer_On[ timer_num]){
      res =false;
    }
  }
  if( res == false ) {
    for ( byte timer_num = 0 ; timer_num <  DEVICE_NUMBER_OF_TIMERS ; ++timer_num){
      if ( Timer_On[ timer_num]){
        if (  ( Cur_Hr > Start_Timer_HR[ timer_num] ||
          ( Cur_Hr == Start_Timer_HR[ timer_num]  && Cur_Min >= Start_Timer_MIN[ timer_num] ) ) &&
          ( Cur_Hr < End_Timer_HR[ timer_num] ||
          ( Cur_Hr == End_Timer_HR[ timer_num]  && Cur_Min <= End_Timer_MIN[ timer_num] ) ) 
          ) {
          res = true;
        }       
      }
    }
  }
  return res;
}

// return true if the device should be turn on / turn off
bool Aquarium_Device::Check_Temp( byte Mode){
  bool res = false;
  for ( byte probe_num = 0; probe_num < TEMP_NUMBER_OF_PROBES ; ++probe_num ){
    if ( Temp_High_Mode[probe_num ] == Mode){
      float Temp = temp.get_temp(probe_num);
      if ( Temp_switch ) {
        res = Temp + Temp_His[probe_num ] > Temp_High[probe_num ];
      } 
      else {
        res = Temp > Temp_High[probe_num ];
      }
    }
    if ( Temp_Low_Mode[probe_num ] == Mode && !res){
      float Temp = temp.get_temp(probe_num);
      if ( Temp_switch ) {
        res = Temp < Temp_Low[probe_num ] + Temp_His[probe_num ] ;
      } 
      else {
        res = Temp < Temp_Low[probe_num ] ;
      }
    }
  }
  return res;
}

void  Aquarium_Device::update(){
  byte Cur_Hr = clock.get_hr();
  byte Cur_min = clock.get_min();
  byte Cur_sec = clock.get_sec();
  byte Aquarium_mode = aquarium_modes.get_Aquarium_mode();
  if (   Device_Mode == DEVICE_MODE_OFF ) {
    Turn_Off();
    Temp_switch = false;
  }
  else if (   Device_Mode == DEVICE_MODE_ON ) {
    Turn_On();
    Temp_switch = false;
  }
  else {
    //check Aquarium modes
    if (  !Check_Aquarium_mode(Aquarium_mode)  ) {
      Turn_Off();
      Temp_switch = false;
    } 
    else if ( Check_Temp(DEVICE_TEMP_MODE_TURN_OFF) ) {
      Turn_Off();
      Temp_switch = true;
    }    
    else if ( Check_Temp(DEVICE_TEMP_MODE_TURN_ON) ) {
      Turn_On();
      Temp_switch = true;
    } 
    else if (  Check_Timer(Cur_Hr,Cur_min)  ) {
      Turn_On();
      Temp_switch = false;
    } 
    else {
      Turn_Off();
      Temp_switch = false;
    }
  }
}



void Aquarium_Device::Key_Prass(byte index,char Key){
  if ( DEVICE_PRINT_START_INDEX_MODE <= index && 
    index <= DEVICE_PRINT_END_INDEX_MODE ){
    if ( (Key == '6') && (Device_Mode < (DEVICE_MODE_NUMBER-1) ) ){
      ++Device_Mode;
    }
    if ( (Key == '4') && (Device_Mode > 0  )  ){
      --Device_Mode;
    }  
  } 
  else if ( DEVICE_PRINT_START_INDEX_MODES <= index && 
    index <= DEVICE_PRINT_END_INDEX_MODES ){
    byte mode = index - DEVICE_PRINT_START_INDEX_MODES;
    if ( Key == '6') {
      Set_Aquarium_mode(mode,1);
    }
    if ( Key == '4' ){
      Set_Aquarium_mode(mode,0);
    }  
  }  
  else if ( DEVICE_PRINT_START_INDEX_TIMER <= index && 
    index <= DEVICE_PRINT_END_INDEX_TIMER ){
    byte offset = index - DEVICE_PRINT_START_INDEX_TIMER;
    byte timer = (offset/3);
    switch (offset%3){
    case 0:
      if ( Key == '6') {
        Timer_On[timer] = true;
      }
      if ( Key == '4' ){
        Timer_On[timer] = false;
      }  
      break;
    case 1:
      if ( Key == '6') {
        Start_Timer_MIN[timer]  = (Start_Timer_MIN[timer] + 1) %60;
      }
      if ( Key == '4' ){
        if ( Start_Timer_MIN[timer] == 0  ) {
          Start_Timer_MIN[timer] = 59;
        }
        else { 
          --Start_Timer_MIN[timer] ;
        }
      }  
      if ( Key == '3') {
        Start_Timer_HR[timer]  = (Start_Timer_HR[timer]  +1 ) %24;
      }
      if ( Key == '1' ){
        if ( Start_Timer_HR[timer] == 0 ){
          Start_Timer_HR[timer]  = 23;
        } 
        else { 
          --Start_Timer_HR[timer] ;
        }
      }  
      break;
    case 2:
      if ( Key == '6') {
        End_Timer_MIN[timer]  = (End_Timer_MIN[timer] + 1) %60;
      }
      if ( Key == '4' ){
        if ( End_Timer_MIN[timer] == 0 ) {
          End_Timer_MIN[timer] = 59;
        }
        else { 
          --End_Timer_MIN[timer] ;
        }
      }  
      if ( Key == '3') {
        End_Timer_HR[timer]  = (End_Timer_HR[timer]  +1 ) %24;
      }
      if ( Key == '1' ){
        if ( End_Timer_HR[timer] == 0 ){
          End_Timer_HR[timer]  = 23;
        } 
        else { 
          --End_Timer_HR[timer] ;
        }
      }  
      break;
    }
  } 
  else if ( DEVICE_PRINT_START_INDEX_TEMP <= index && 
    index <= DEVICE_PRINT_END_INDEX_TEMP ){
    byte offset = index - DEVICE_PRINT_START_INDEX_TEMP;
    byte probe_num = (offset/DEVICE_PRINT_TEMP_LEN);

    switch (offset%DEVICE_PRINT_TEMP_LEN){
    case 0:
      break;
    case 1:
      if ( Key == '6') {
        Temp_His_byte[probe_num]  = (Temp_His_byte[probe_num]  +10 ) %250;
      }
      if ( Key == '4' ){
        if ( Temp_His_byte[probe_num] == 0 ){
          Temp_His_byte[probe_num]  = 240;
        } 
        else { 
          Temp_His_byte[probe_num] -= 10 ;
        }
      }  
      Temp_His[probe_num] = ((float)Temp_His_byte[probe_num])  / 100;
      break;
    case 2:
      if ( (Key == '6') && (Temp_High_Mode[probe_num] < (DEVICE_TEMP_MODE_NUMBER-1) ) ){
        ++Temp_High_Mode[probe_num];
      }
      if ( (Key == '4') && (Temp_High_Mode[probe_num] > 0  )  ){
        --Temp_High_Mode[probe_num];
      }  
      break;
    case 3:
      if ( Key == '6') {
        Temp_High_h[probe_num]  = (Temp_High_h[probe_num] + 1) %100;
      }
      if ( Key == '4' ){
        if ( Temp_High_h[probe_num] == 0  ) {
          Temp_High_h[probe_num] = 99;
        }
        else { 
          --Temp_High_h[probe_num] ;
        }
      }  
      if ( Key == '3') {
        Temp_High_l[probe_num]  = (Temp_High_l[probe_num]  +10 ) %100;
      }
      if ( Key == '1' ){
        if ( Temp_High_l[probe_num] == 0 ){
          Temp_High_l[probe_num]  = 90;
        } 
        else { 
          Temp_High_l[probe_num]  -= 10 ;
        }
      }  
      Temp_High[probe_num] = temp.get_temp(Temp_High_h[probe_num],Temp_High_l[probe_num]);
      break;
    case 4:
      if ( (Key == '6') && (Temp_Low_Mode[probe_num] < (DEVICE_TEMP_MODE_NUMBER-1) ) ){
        ++Temp_Low_Mode[probe_num];
      }
      if ( (Key == '4') && (Temp_Low_Mode[probe_num] > 0  )  ){
        --Temp_Low_Mode[probe_num];
      }  
      break;
    case 5:
      if ( Key == '6') {
        Temp_Low_h[probe_num]  = (Temp_Low_h[probe_num] + 1) %100;
      }
      if ( Key == '4' ){
        if ( Temp_Low_h[probe_num] == 0  ) {
          Temp_Low_h[probe_num] = 99;
        }
        else { 
          --Temp_Low_h[probe_num] ;
        }
      }  
      if ( Key == '3') {
        Temp_Low_l[probe_num]  = (Temp_Low_l[probe_num]  +10 ) %100;
      }
      if ( Key == '1' ){
        if ( Temp_Low_l[probe_num] == 0 ){
          Temp_Low_l[probe_num]  = 90;
        } 
        else { 
          Temp_Low_l[probe_num]  -= 10 ;
        }
      }  
      Temp_Low[probe_num] = temp.get_temp(Temp_Low_h[probe_num],Temp_Low_l[probe_num]);
      break;
    }
  } 
}

void Aquarium_Device::Print(byte index){
  if ( DEVICE_PRINT_START_INDEX_MODE <= index && 
    index <= DEVICE_PRINT_END_INDEX_MODE ){
    lcd.print("Device Mode : ");
    switch (Device_Mode){
    case DEVICE_MODE_OFF:
      Print_OFF();
      break;
    case DEVICE_MODE_ON:
      Print_ON();
      break;
    case DEVICE_MODE_AUTO:
      lcd.print("AUTO");
      break;
    }
  } 
  else if ( DEVICE_PRINT_START_INDEX_MODES <= index && 
    index <= DEVICE_PRINT_END_INDEX_MODES ){
    byte mode = index - DEVICE_PRINT_START_INDEX_MODES;
    aquarium_modes.Print(mode);
    lcd.print(" : ");
    if ( Check_Aquarium_mode(mode) ){
      Print_ON();
    } 
    else {
      Print_OFF();
    }
  }
  else if ( DEVICE_PRINT_START_INDEX_TIMER <= index && 
    index <= DEVICE_PRINT_END_INDEX_TIMER ){
    byte offset = index - DEVICE_PRINT_START_INDEX_TIMER;
    byte timer = (offset/DEVICE_PRINT_TIMERS_LEN);

    switch (offset%DEVICE_PRINT_TIMERS_LEN){
    case 0:
      lcd.print("Timer ");
      lcd.print((int)timer+1);
      lcd.print(" Mode :");
      if (Timer_On[timer] == false){
        Print_OFF();
      } 
      else {
        Print_ON();
      }
      break;
    case 1:
      lcd.print(" Start Time : ");
      clock.print_time_min(Start_Timer_HR[timer],Start_Timer_MIN[timer]);
      break;
    case 2:
      lcd.print(" End Time   : ");
      clock.print_time_min(End_Timer_HR[timer],End_Timer_MIN[timer]);
      break;
    }
  } 
  else if ( DEVICE_PRINT_START_INDEX_TEMP <= index && 
    index <= DEVICE_PRINT_END_INDEX_TEMP ){
    byte offset = index - DEVICE_PRINT_START_INDEX_TEMP;
    byte probe_num = (offset/DEVICE_PRINT_TEMP_LEN);

    switch (offset%DEVICE_PRINT_TEMP_LEN){
    case 0:
      temp.print_probe_name(probe_num);
      lcd.print(":");
      break;
    case 1:
      lcd.print(" His:");
      temp.print_temp(Temp_His[probe_num]);
      break;
    case 2:
      lcd.print(" High Mode:");
      switch (Temp_High_Mode[probe_num]){
      case DEVICE_TEMP_MODE_OFF:
        Print_OFF();
        break;
      case DEVICE_TEMP_MODE_TURN_OFF:
        lcd.print("TURN OFF");
        break;
      case DEVICE_TEMP_MODE_TURN_ON:
        lcd.print("TURN ON");
        break;
      }
      break;
    case 3:
      lcd.print(" High Temp:");
      temp.print_temp(Temp_High[probe_num]);
      break;
    case 4:
      lcd.print(" Low Mode:");
      switch (Temp_Low_Mode[probe_num]){
      case DEVICE_TEMP_MODE_OFF:
        Print_OFF();
        break;
      case DEVICE_TEMP_MODE_TURN_OFF:
        lcd.print("TURN OFF");
        break;
      case DEVICE_TEMP_MODE_TURN_ON:
        lcd.print("TURN ON");
        break;
      }
      break;
    case 5:
      lcd.print(" Low Temp:");
      temp.print_temp(Temp_Low[probe_num]);
      break;
    }

  } 
}











































